#include "profilemanager.h"
#include "constantapp.h"
#include "accountmanager.h"
#include "network/networkmanager.h"
#include "network/networkhttprequest.h"
#include "network/networkresponse.h"
#include "profile/getfriendrequest.h"
#include "profile/getfriendresponse.h"
#include "profile/multigetprofilerequest.h"
#include "profile/multigetprofileresponse.h"
#include "profile/getmessagestatusrequest.h"
#include "profile/getmessagestatusresponse.h"
#include "profile/getonlinefriendrequest.h"
#include "profile/getonlinefriendresponse.h"
#include "contact/contactmanager.h"
#include "contact/contactprivatecontact.h"
#include "contact/contactgroupcontact.h"

#include "group/createnewgrouprequest.h"
#include "event/createnewgroupevent.h"
#include "parser/createnewgroupparser.h"

#include "sqlite/friendprofiletable.h"

#include <QDir>
#include <QDebug>


ProfileManager::ProfileManager(QObject *parent)
    : QObject(parent),
      _listFriendOnGroup(),
      _listFriendProfile(),
      _mapFriendProfile(),
      _idxAvatarDownload(0),
      _idxAvatarFrom(0),
      _idxAvatarTo(0),
      m_updateOnlineStatusTimer(NULL),
      m_onlineFriendRequest(NULL)
{
    m_insertProfileThread = new InsertProfileThread;
    m_updateMsgThread = new UpdateMessageStatusThread;
}

ProfileManager *ProfileManager::m_instance = NULL;

ProfileManager *ProfileManager::instance(QObject *parent)
{
    if (m_instance == NULL)
        m_instance = new ProfileManager(parent);
    return m_instance;
}

void ProfileManager::init()
{
    // get tu local truoc sau do moi get data tu integer
    _listFriendProfile = Sqlite::FriendProfileTable::getAllFriendProfile();

    /* cho nay chua dung
     * - khi chua get het friend da logout,
     * - phai gui them request lay friend con thieu
     */

    if(_listFriendProfile.size() > 0){
        for(int i = 0; i< _listFriendProfile.size(); ++i){
            UserProfile* uProfile = _listFriendProfile.at(i);
            _mapFriendProfile[uProfile->getUserId()] = uProfile;
            if (uProfile->getTotalMember() == 1) {
                Contact::PrivateContact*privateC = new Contact::PrivateContact(uProfile->getUserId());
                Contact::Manager::instance()->append(privateC);
            } else if (uProfile->getTotalMember() >1) {
                Contact::GroupContact *groupContact = new Contact::GroupContact(uProfile->getUserId());
                Contact::Manager::instance()->append(groupContact);
            }
        }
        emit getUnitFriendsProfile(_listFriendProfile);

        emit startGetListFriendSortByName();

        doGetOnlineFriendsRequest();

    }else{
        doGetAllFriendIdRequest(1);
    }
}

void ProfileManager::clearData()
{
    delete m_insertProfileThread;
    delete m_updateMsgThread;
    delete m_updateOnlineStatusTimer;
    m_updateOnlineStatusTimer = NULL;

    int countFriend = _listFriendProfile.length();
    if (countFriend == 0)
        return;

    for ( int i =0; i < countFriend; i++) {
        UserProfile* aUser = _listFriendProfile.first();
        _listFriendProfile.removeFirst();
        delete aUser;
    }

    _listFriendProfile.clear();
    _mapFriendProfile.clear();


    // remove Database avatar
    //    Sqlite::FriendProfileTable::clearTable();

    //    QString currentPathAvatar = QDir::currentPath();
    //    currentPathAvatar.append("/MeQml/Avatar/");
    //    QDir *avatarDir = new QDir(currentPathAvatar);
    //    avatarDir->removeRecursively();

}

void ProfileManager::setConnection()
{

}

void ProfileManager::sortListFriendAgain(qint64 fid)
{
    UserProfile* aFriendProfile = ProfileManager::instance()->getProfileById(fid);
    removeProfileFriend(fid);

    _listFriendProfile.insert(0, aFriendProfile);

    emit refreshCurrentListFriendSuccessfull();

}


void ProfileManager::doGetAllFriendIdRequest(const int page)
{
    UserProfile* uProfile = AccountManager::instance()->getUserProfile();
    if( uProfile == NULL){
        return ;
    }

    GetFriendIdRequest *request = new GetFriendIdRequest(uProfile->getUserId(),  page);
    connect(request, &GetFriendIdRequest::responded,
            this, &ProfileManager::onGetAllFriendIdResponsed);

    Network::Manager *manager = Network::Manager::instance();
    if (!manager->post(request)) {
        delete request;
        request = 0;
    }
}

void ProfileManager::updateFriendProfile(Converse::AbstractMessage *message)
{
    int typeMsg = 1;// message sent, or recieve
    qint64 fid = -1;
    int senderMsg = -1;
    if (message->senderId() == AccountManager::instance()->getUserId()) {
        senderMsg = 1;
        fid = message->receiverId();
    } else {
        senderMsg = 0;
        fid = message->senderId();
    }
    // update on DB
    //    Sqlite::FriendProfileTable::updateMessageStatus(fid,
    //                                                    senderMsg,
    //                                                    message->message(),
    //                                                    message->receivedTime(),
    //                                                    typeMsg);

    // Update on cache
    UserProfile* aFriendProfile = ProfileManager::instance()->getProfileById(fid);
    aFriendProfile->setMessageStatus(message->message());
    aFriendProfile->setSenderMsg(senderMsg);
    aFriendProfile->setTypeMsg(typeMsg);

    qint64 time = message->receivedTime();
    //    QDateTime dateTime;
    //    dateTime.setMSecsSinceEpoch(time * 1000);
    //    QString timeString = dateTime.toString("hh:mm AP");

    aFriendProfile->setTime(time);
    aFriendProfile->setTypeMsg(typeMsg);

    m_updateMsgThread->pushMsgStatusFriendProfile(aFriendProfile);
    if (!m_updateMsgThread->isRunning()) {
        m_updateMsgThread->start();
    }

    // sort list friends
    sortListFriendAgain(fid);
}


void ProfileManager::updateFriendProfile(const qint64 fid,
                                         const int senderMsg,
                                         const QString msgStatus,
                                         const qint64 time)
{
    int typeMsg = 0;// message status
    // update on DB
    //    Sqlite::FriendProfileTable::updateMessageStatus(fid,
    //                                                    senderMsg,
    //                                                    msgStatus,
    //                                                    time,
    //                                                    typeMsg);

    // Update on cache
    UserProfile* aFriendProfile = ProfileManager::instance()->getProfileById(fid);
    aFriendProfile->setMessageStatus(msgStatus);
    aFriendProfile->setSenderMsg(senderMsg);
    aFriendProfile->setTypeMsg(typeMsg);

    //    qint64 time64 = time;
    //    QDateTime dateTime;
    //    dateTime.setMSecsSinceEpoch(time64 * 1000);
    //    QString timeString = dateTime.toString("hh:mm AP");

    aFriendProfile->setTime(time);



    m_updateMsgThread->pushMsgStatusFriendProfile(aFriendProfile);
    if (!m_updateMsgThread->isRunning()) {
        m_updateMsgThread->start();
    }

}


void ProfileManager::onGetAllFriendIdResponsed(Network::HttpRequest *request)
{

    GetFriendIdRequest *constRequest = (GetFriendIdRequest*)request;
    const GetFriendIdResponse &friendResponse = (const GetFriendIdResponse&)(constRequest->response());
    const GetFriendIdResponse::ListUserId &idList = friendResponse.getListUserId();

    if (!idList.isEmpty()) {
        foreach (qint64 id, idList) {
            UserProfile *uProfile = new UserProfile();
            uProfile->setUserId(id);
            _listFriendProfile.push_back(uProfile);

            _mapFriendProfile[id] = uProfile;
        }
        qDebug() << "ProfileManager::onGetAllFriendIdResponded page "<< constRequest->page();
        int page = constRequest->page() +1;
        doGetAllFriendIdRequest(page);

    } else {
        // get profile
        doGetAllProfileFriendRequest(0,20);

    }
}

void ProfileManager::doGetAllProfileFriendRequest(const int idx, const int count ){
    UserProfile* uProfile = AccountManager::instance()->getUserProfile();
    if( uProfile == NULL){
        return ;
    }
    std::vector<qint64> listUserId;
    for(int i = 0; i< count ; i++){
        int idxGet = idx + i;
        if(_listFriendProfile.size() > idxGet){
            listUserId.push_back(_listFriendProfile.at(idxGet)->getUserId());
        }else{
            break;
        }
    }

    MultiGetProfileRequest *request = new MultiGetProfileRequest(listUserId,  AccountManager::instance()->getSessionKey(), idx, count);
    connect(request, &MultiGetProfileRequest::responded,
            this, &ProfileManager::onGetAllProfileFriendResponsed);

    Network::Manager *manager = Network::Manager::instance();
    if (!manager->post(request)) {
        delete request;
        request = 0;
    }
}

void ProfileManager::onGetAllProfileFriendResponsed(Network::HttpRequest *request){

    MultiGetProfileRequest *constRequest = (MultiGetProfileRequest*)request;
    const MultiGetProfileResponse &friendResponse = (const MultiGetProfileResponse&)(constRequest->response());
    const QList<UserProfile*> &listProfile = friendResponse.getListUserProfile();

    if (!listProfile.empty()) {
        //emit getUnitFriendsProfile(listProfile);
        // update lai cache
        foreach (UserProfile* uProfile, listProfile) {
            UserProfile* uOldProfile = getProfileById(uProfile->getUserId());
            if(uOldProfile){
                uOldProfile->setBaseInfo(uProfile->getUserId(),
                                         uProfile->getUserName(),
                                         uProfile->getDisplayName(),
                                         uProfile->getAvatar());
                // uOldProfile->updateData2Local();
                Contact::PrivateContact*privateC = new Contact::PrivateContact(uProfile->getUserId());
                Contact::Manager::instance()->append(privateC);
            }
        }
        // download avatar .
        _idxAvatarFrom = constRequest->m_idx;
        qDebug() << "ProfileManager::doGetAllProfileFriendResponsed page "<< constRequest->m_idx;
        _idxAvatarTo  = constRequest->m_idx +constRequest->m_count;

        if(_idxAvatarFrom == 0){
            // show ra luon khong doi down ve nua
            emit getUnitFriendsProfile(listProfile);
        }
        doGetAvatarAndUpdateFriend();

        //emit startGetListFriendSortByNameFirstTime();



    } else {
        // get profile
        qDebug() << "ProfileManager::getAllFriendProfileFinish idx "<< constRequest->m_idx;
        doGetProfileFinish();



    }
}

QList<UserProfile*> ProfileManager::getListFriendsProfileSortByNameFirtTime() const {
    QList<UserProfile*> listUserProfile;
    listUserProfile.clear();

    for (int i = 0; i < _listFriendProfile.length(); i++) {
        UserProfile* aUserProfile = _listFriendProfile.at(i);
        listUserProfile.append(aUserProfile);
    }
    //qSort(listUserProfile, listUserProfile.begin(), listUserProfile.end());



    for (int i=0; i< listUserProfile.length(); i++)
    {
        UserProfile* iUserProfile = listUserProfile.at(i);
        for (int j =0; j < listUserProfile.length(); j++)
        {
            UserProfile* jUserProfile = listUserProfile.at(j);
            if (iUserProfile->getDisplayName().trimmed().toUpper() <=
                    jUserProfile->getDisplayName().trimmed().toUpper())
            {
                UserProfile* tempUserProfile =listUserProfile[j];
                //                listUserProfile.insert(j, iUserProfile);
                //                listUserProfile.removeAt(j);

                //                listUserProfile.insert(i, tempUserProfile);
                //                listUserProfile.removeAt(i);

                listUserProfile[j] = listUserProfile[i];
                listUserProfile[i] = tempUserProfile;
            }
        }
    }

    //    for (int i=0; i< listUserProfile.length(); i++)
    //    {
    //        qDebug()<< "============" <<i << " : " <<listUserProfile.at(i)->getDisplayName();
    //    }


    return listUserProfile;
}

QList<UserProfile*> ProfileManager::getListFriendsProfileSortByName() const {
    return Sqlite::FriendProfileTable::friendListSortByName();
}

QList<UserProfile*> ProfileManager::getListFriendProfile() const {
    return _listFriendProfile;
}

QList<UserProfile*> ProfileManager::getRefreshListFriendProfile() const {
    return Sqlite::FriendProfileTable::refreshListFriends();
}

QList<UserProfile*> ProfileManager::getSearchFriends(QString inputName) const {
    return Sqlite::FriendProfileTable::searchFriendsFTS(inputName);
}


UserProfile* ProfileManager::getProfileById(const qint64 userId){
    QMap<qint64, UserProfile*>::iterator iter = _mapFriendProfile.find(userId);
    if(iter != _mapFriendProfile.end() && iter.key() == userId){
        return iter.value();
    }
    return NULL;
}

void ProfileManager::removeProfileFriend(const qint64 fid)
{
    UserProfile* aFriendProfile;
    for (int i= 0; i < _listFriendProfile.length(); i++) {
        aFriendProfile = _listFriendProfile.at(i);
        if (aFriendProfile->getUserId() == fid) {
            _listFriendProfile.removeAt(i);

            break;
        }
    }
}

void ProfileManager::doGetProfileFinish()
{
    // qDebug() <<  "doGetProfileFinish";
    emit getAllFriendProfileFinish();
    doUpdateFriend2Local();
    //thuc hien get Avatar

}

void ProfileManager::doUpdateFriend2Local()
{
    // qDebug() <<  "doUpdateFriend2Local";
    UserProfile* uProfile = getUserProfileByIdx(_idxAvatarDownload);
    if(uProfile){
        connect(uProfile, &UserProfile::updateLocalFinish,
                this, &ProfileManager::onUpdateAFriendFinish );
        uProfile->updateData2Local();
    }
}




void ProfileManager::onUpdateAFriendFinish(){
    _idxAvatarDownload ++;
    qDebug() << " idxAvatar " << _idxAvatarDownload << " to " << "_idxAvatarTo" << _idxAvatarTo ;
    if(_idxAvatarDownload >= _idxAvatarTo){
        doGetUnitFriendsProfileFinish(_idxAvatarFrom, _idxAvatarTo);
        if(_idxAvatarTo > _listFriendProfile.size()){
            doGetProfileFinish();
        }else{
            doGetAllProfileFriendRequest(_idxAvatarTo, 30);
        }
    }
    doGetAvatarAndUpdateFriend();
}

void ProfileManager::doGetOnlineFriendsRequest()
{
    if (m_updateOnlineStatusTimer == NULL) {
        m_updateOnlineStatusTimer = new QTimer(this);
    }

    m_updateOnlineStatusTimer->start(1000 * 30);

    connect(m_updateOnlineStatusTimer,
            &QTimer::timeout,
            this,
            &ProfileManager::onOnlineFriendsRequestTimerTimeout);
}

void ProfileManager::onOnlineFriendsRequestTimerTimeout()
{
    qDebug() << "================ onOnlineFriendsRequestTimerTimeout";

    QString sessionKey = Network::Manager::instance()->sessionKey();
    GetOnlineFriendRequest *request = new GetOnlineFriendRequest(sessionKey);
    connect(request,
            &GetOnlineFriendRequest::responded,
            this,
            &ProfileManager::onGetOnlineFriendsResponsed);

    Network::Manager *manager = Network::Manager::instance();
    if (!manager->post(request)) {
        delete request;
        request = NULL;
        return;
    }
}

void ProfileManager::onGetOnlineFriendsResponsed(Network::HttpRequest *request)
{
    QList <UserProfile*> listFriendsOnline;

    const Network::HttpRequest &constRequest = *request;
    const Network::Response &response = constRequest.response();

    const GetOnlineFriendResponse &onlineFriendsResponse = \
            (const GetOnlineFriendResponse &)response;
    const GetOnlineFriendResponse::ItemList &onlineFriends = onlineFriendsResponse.items();

    for (int i=0; i < _listFriendProfile.length(); i++) {
        UserProfile* aUserProfile = _listFriendProfile.at(i);
        aUserProfile->setOnline(UserProfile::Offline);
    }


    for (int i=0; i < onlineFriends.length(); i++) {
        GetOnlineFriendResponse::Item* item;
        item = onlineFriends.at(i);

        UserProfile* aUserProfile = getProfileById(item->id());

        if (aUserProfile != NULL) {

            if (item->mobileTime() == 0 && item->webTime() == 0) {
                aUserProfile->setOnline(UserProfile::Offline);
            } else if (item->mobileTime() > 0) {
                aUserProfile->setOnline(UserProfile::OnlineMobile);
            } else if (item->webTime() > 0) {
                aUserProfile->setOnline(UserProfile::OnlineWeb);
            }

            qDebug() << "++++++++++++++++++++++++++++++" << aUserProfile->getUserId();

            listFriendsOnline.append(aUserProfile);
        }
    }

    emit getAllFriendsOnline(listFriendsOnline);
}

void ProfileManager::doGetMessageStatusFirstTimeLogin(qint64 fid)
{
    QString sessionKey = Network::Manager::instance()->sessionKey();
    GetMessageStatusRequest *request = new GetMessageStatusRequest(fid,
                                                                   sessionKey);
    connect(request,
            &GetMessageStatusRequest::responded,
            this,
            &ProfileManager::onGetMessageStatusResponsed);

    Network::Manager *manager = Network::Manager::instance();
    if (!manager->post(request)) {
        delete request;
        request = NULL;
        return;
    }
}

void ProfileManager::onGetMessageStatusResponsed(Network::HttpRequest *request)
{
    const Network::HttpRequest &constRequest = *request;
    const Network::Response &response = constRequest.response();

    const GetMessageStatusResponse &messageStatusResponse = \
            (const GetMessageStatusResponse &)response;

    QString messageStatus = messageStatusResponse.messageStatus();

    
    qDebug() <<"+++++++++++++++++++++++++++++msg status " + messageStatus;
    
    if (messageStatus.length() != 0) {

        updateFriendProfile(messageStatusResponse.getfid(),
                            0,
                            messageStatus,
                            0);
    }

    request->deleteLater();
}

void ProfileManager::doGetAvatarAndUpdateFriend(){
    if(_idxAvatarDownload < _idxAvatarTo && _idxAvatarDownload < _listFriendProfile.size()){
        //downimage and update avatar
        UserProfile* uProfile = getUserProfileByIdx(_idxAvatarDownload);
        if(uProfile){
            connect(uProfile, &UserProfile::updateLocalFinish,
                    this, &ProfileManager::onUpdateAFriendFinish );

            uProfile->updateData2Local();

            if (uProfile == _listFriendProfile.last()) {
                emit startGetListFriendSortByNameFirstTime();
            }
        }
        doGetMessageStatusFirstTimeLogin(uProfile->getUserId());
    }
}

void ProfileManager::doGetUnitFriendsProfileFinish(const int idxFrom, const int idxTo){
    // truong hop = 0 emit ra luon khong doi download
    if(idxFrom != 0){
        QList<UserProfile* > listUserProfile;
        for(int idx = idxFrom ; idx <idxTo; ++idx){
            if(idx < _listFriendProfile.size()){
                listUserProfile.push_back(_listFriendProfile[idx]);
            }
        }
        emit getUnitFriendsProfile(listUserProfile);
    }
}


UserProfile* ProfileManager::getUserProfileByIdx(const int idx){
    if(idx < _listFriendProfile.size()){
        return _listFriendProfile[idx];
    }
    return NULL;
}

void ProfileManager::addFriendToGroup(qint64 uid, qint64 fid)
{
    Q_UNUSED(uid);

    UserProfile* userProfile = getProfileById(fid);
    if (userProfile == NULL)
        return;
    _listFriendOnGroup.append(userProfile);
}

void ProfileManager::deleteFriendFromGroup(qint64 uid, qint64 fid)
{
    Q_UNUSED(uid);

    int cs = -1;
    for (int i=0; i < _listFriendOnGroup.length(); i++) {
        if (_listFriendOnGroup.at(i)->getUserId() == fid) {
            cs = i;
            break;
        }
    }
    if (cs != -1) {
        _listFriendOnGroup.removeAt(cs);
    }
}

void ProfileManager::doCreateGroup(QString groupName)
{
    if (_listFriendOnGroup.length() == 0)
        return;

    QString listId = "";
    for (int i=0;i <_listFriendOnGroup.length(); i++) {
        listId.append(QVariant(_listFriendOnGroup.at(i)->getUserId()).toString());
        listId.append(QString(","));
    }
    listId.remove(listId.length() - 1 , 1);

    CreateNewGroupRequest* createNewGroupRequest = \
            new CreateNewGroupRequest(groupName, listId, this);

    Network::Manager *manager = Network::Manager::instance();
    if (!manager->post(createNewGroupRequest)) {
        delete createNewGroupRequest;
        createNewGroupRequest = 0;
        return;
    }

    return;
}


void ProfileManager::createNewGroupEvent(const CreateNewGroupEvent &aCreateNewGroupEvent)
{
    qint64 groupId = aCreateNewGroupEvent.getGroupId();
    int countUser = aCreateNewGroupEvent.getCountUser();
    QList <qint64> lisFids = aCreateNewGroupEvent.getListFids();
    QString groupName = aCreateNewGroupEvent.getGroupName();

    UserProfile *uProfile = new UserProfile();
    uProfile->setUserId(groupId);
    uProfile->setBaseInfo(groupId, groupName, groupName, "qrc:/images/resources/icon.png");
    uProfile->setTotalMember(countUser);
    uProfile->setListGroupMember(lisFids);

    Contact::GroupContact *groupContact = new Contact::GroupContact(groupId);
    Contact::Manager::instance()->append(groupContact);

    _listFriendProfile.push_back(uProfile);

    _mapFriendProfile[groupId] = uProfile;

    m_insertProfileThread->insertFriendProfile(uProfile);
    if (!m_insertProfileThread->isRunning()) {
        m_insertProfileThread->start();
    }


    emit createNewGroupSucessfull();
}


